// MailNoter - A capture tool for emails

// Copyright (C) 2009 - MailNoter

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
#include "stdafx.h"
#include "MailMsg.h"

CMailMsg::CMailMsg()
{
	m_lpMapiLogon     = NULL;
	m_lpMapiSendMail  = NULL;
	m_lpMapiLogoff    = NULL;
	m_lpMapiResolveName = NULL;
	m_lpMapiFreeBuffer = NULL;
	m_bReady          = FALSE;
}

CMailMsg::~CMailMsg()
{
	if (m_bReady)
		Uninitialize();
}

CMailMsg& CMailMsg::SetFrom(std::string sAddress, std::string sName)
{
	if (m_bReady || Initialize())
	{
		// only one sender allowed
		if (m_from.size())
			m_from.empty();

		m_from.push_back(TStrStrPair(sAddress,sName));
	}

	return *this;
}

CMailMsg& CMailMsg::SetTo(std::string sAddress, std::string sName)
{
	if (m_bReady || Initialize())
	{
		// only one recipient allowed
		if (m_to.size())
			m_to.empty();

		m_to.push_back(TStrStrPair(sAddress,sName));
	}

	return *this;
}

CMailMsg& CMailMsg::SetCc(std::string sAddress, std::string sName)
{
	if (m_bReady || Initialize())
	{
		m_cc.push_back(TStrStrPair(sAddress,sName));
	}

	return *this;
}

CMailMsg& CMailMsg::SetBc(std::string sAddress, std::string sName)
{
	if (m_bReady || Initialize())
	{
		m_bcc.push_back(TStrStrPair(sAddress, sName));
	}

	return *this;
}

CMailMsg& CMailMsg::AddAttachment(std::string sAttachment, std::string sTitle)
{
	if (m_bReady || Initialize())
	{
		m_attachments.push_back(TStrStrPair(sAttachment, sTitle));
	}

	return *this;
}

BOOL CMailMsg::Send()
{
	int status = MAPISend();
	if (status != 0)
		return status == 1;

	return FALSE;
}

int CMailMsg::cResolveName(LHANDLE m_lhSession, const char * lpszName, lpMapiRecipDesc *ppRecip)
{	
	HRESULT hRes = E_FAIL;
	FLAGS flFlags = 0L;
	ULONG ulReserved = 0L;
	lpMapiRecipDesc pRecips = NULL;

	// Always check to make sure there is an active session
	if (m_lhSession)		
	{
		hRes = m_lpMapiResolveName (
			m_lhSession,	// Session handle
			0L,			// Parent window.
			const_cast<LPSTR>(lpszName),		// Name of recipient.  Passed in by argv.
			flFlags,		// Flags set to 0 for MAPIResolveName.
			ulReserved,
			&pRecips
			);				

		if  (hRes == SUCCESS_SUCCESS)
		{  
			// Copy the recipient descriptor returned from MAPIResolveName to 
			// the out parameter for this function,
			*ppRecip = pRecips;
		}  
	}
	return hRes;
}

int CMailMsg::MAPISend()
{

	TStrStrVector::iterator p;
	int                  nIndex = 0;
	size_t               nRecipients = 0;
	MapiRecipDesc*       pRecipients = NULL;
	MapiRecipDesc*       pOriginator = NULL;
	MapiRecipDesc*       pFirstRecipient = NULL;
	size_t               nAttachments = 0;
	MapiFileDesc*        pAttachments = NULL;
	ULONG                status = 0;
	MapiMessage          message;
	std::vector<MapiRecipDesc*>	buffersToFree;
	MapiRecipDesc*       pRecip;
	MapiRecipDesc		grecip;

	if (m_bReady || Initialize())
	{
		LHANDLE hMapiSession;
		status = m_lpMapiLogon(NULL, NULL, NULL, MAPI_NEW_SESSION | MAPI_LOGON_UI, 0, &hMapiSession);
		if (SUCCESS_SUCCESS != status) 
		{
			return FALSE;
		}

		nRecipients = m_to.size() + m_cc.size() + m_bcc.size() + m_from.size();
		if (nRecipients)
		{
			pRecipients = new MapiRecipDesc[nRecipients];
			memset(pRecipients, 0, nRecipients * sizeof  MapiRecipDesc);
		}

		nAttachments = m_attachments.size();
		if (nAttachments)
			pAttachments = new MapiFileDesc[nAttachments];

		if (pRecipients)
		{
			pFirstRecipient = pRecipients;
			if (m_from.size())
			{
				// set from
				if (cResolveName(hMapiSession, m_from.begin()->first.c_str(), &pOriginator) == SUCCESS_SUCCESS) 
			 {
				 buffersToFree.push_back(pOriginator);
			 }
			}
			if (m_to.size())
			{
				if (cResolveName(hMapiSession, m_to.begin()->first.c_str(), &pRecip) == SUCCESS_SUCCESS) 
			 {
				 if (pFirstRecipient == NULL)
					 pFirstRecipient = &pRecipients[nIndex];
				 pRecip->ulRecipClass = MAPI_TO;
				 memcpy(&pRecipients[nIndex], pRecip, sizeof pRecipients[nIndex]);
				 buffersToFree.push_back(pRecip);
				 nIndex++;
			 }
				else
			 {
				 if (pFirstRecipient == NULL)
					 pFirstRecipient = &pRecipients[nIndex];
				 grecip.ulRecipClass = MAPI_TO;
				 grecip.lpEntryID = 0;
				 grecip.lpszName = 0;
				 grecip.ulEIDSize = 0;
				 grecip.ulReserved = 0;
				 grecip.lpszAddress = (LPSTR)(LPCSTR)m_to.begin()->first.c_str();
				 memcpy(&pRecipients[nIndex], &grecip, sizeof pRecipients[nIndex]);
				 nIndex++;
			 }
			}		
			if (m_cc.size())
			{
				// set cc's
				for (p = m_cc.begin(); p != m_cc.end(); p++, nIndex++)
				{
					if ( cResolveName(hMapiSession, p->first.c_str(), &pRecip) == SUCCESS_SUCCESS) 
					{
						if (pFirstRecipient == NULL)
							pFirstRecipient = &pRecipients[nIndex];
						pRecip->ulRecipClass = MAPI_CC;
						memcpy(&pRecipients[nIndex], pRecip, sizeof pRecipients[nIndex]);
						buffersToFree.push_back(pRecip);
						nIndex++;
					}
				}
			}

			if (m_bcc.size())
			{
				// set bcc
				for (p = m_bcc.begin(); p != m_bcc.end(); p++, nIndex++)
				{
					if ( cResolveName(hMapiSession, p->first.c_str(), &pRecip) == SUCCESS_SUCCESS) 
					{
						if (pFirstRecipient == NULL)
							pFirstRecipient = &pRecipients[nIndex];
						pRecip->ulRecipClass = MAPI_BCC;
						memcpy(&pRecipients[nIndex], pRecip, sizeof pRecipients[nIndex]);
						buffersToFree.push_back(pRecip);
						nIndex++;
					}
				}
			}
		}
		if (pAttachments)
		{
			// add attachments
			for (p = m_attachments.begin(), nIndex = 0;
				p != m_attachments.end(); p++, nIndex++)
			{
				pAttachments[nIndex].ulReserved        = 0;
				pAttachments[nIndex].flFlags           = 0;
				pAttachments[nIndex].nPosition         = 0;
				pAttachments[nIndex].lpszPathName      = (LPSTR)p->first.c_str();
				pAttachments[nIndex].lpszFileName      = (LPSTR)p->second.c_str();
				pAttachments[nIndex].lpFileType        = NULL;
			}
		}
		memset(&message, 0, sizeof message);
		message.ulReserved                        = 0;
		if (!m_sSubject.empty())
			message.lpszSubject                   = (LPSTR)m_sSubject.c_str();
		else
			message.lpszSubject = "No Subject";
		if (!m_sMessage.empty())
			message.lpszNoteText                  = (LPSTR)m_sMessage.c_str();
		else
			message.lpszNoteText = "No Message Body";
		message.lpszMessageType                   = NULL;
		message.lpszDateReceived                  = NULL;
		message.lpszConversationID                = NULL;
		message.flFlags                           = 0;
		message.lpOriginator                      = pOriginator;
		message.nRecipCount                       = nIndex;
		message.lpRecips                          = pFirstRecipient;
		message.nFileCount                        = nAttachments;
		message.lpFiles                           = pAttachments;

		status = m_lpMapiSendMail(hMapiSession, 0, &message, MAPI_DIALOG, 0);

		m_lpMapiLogoff(hMapiSession, NULL, 0, 0);
		std::vector<MapiRecipDesc*>::iterator iter;
		for (iter = buffersToFree.begin(); iter != buffersToFree.end(); iter++) 
		{
			m_lpMapiFreeBuffer(*iter);
		}

		if (pRecipients)
			delete [] pRecipients;

		if (nAttachments)
			delete [] pAttachments;
	}

	if (SUCCESS_SUCCESS == status)
		return 1;
	if (MAPI_E_USER_ABORT == status)
		return -1;
	// other failure
	return 0;
}

BOOL CMailMsg::Initialize()
{
	m_hMapi = ::LoadLibrary(_T("mapi32.dll"));

	if (!m_hMapi)
		return FALSE;

	m_lpMapiLogon = (LPMAPILOGON)::GetProcAddress(m_hMapi, ("MAPILogon"));
	m_lpMapiSendMail = (LPMAPISENDMAIL)::GetProcAddress(m_hMapi, ("MAPISendMail"));
	m_lpMapiLogoff = (LPMAPILOGOFF)::GetProcAddress(m_hMapi, ("MAPILogoff"));
	m_lpMapiResolveName = (LPMAPIRESOLVENAME) GetProcAddress(m_hMapi, ("MAPIResolveName"));
	m_lpMapiFreeBuffer = (LPMAPIFREEBUFFER) GetProcAddress(m_hMapi, ("MAPIFreeBuffer"));

	m_bReady = (m_lpMapiLogon && m_lpMapiSendMail && m_lpMapiLogoff);

	return m_bReady;
}

void CMailMsg::Uninitialize()
{
	::FreeLibrary(m_hMapi);
}